using System;
using System.Data;
using System.Data.Common;
using Avanzis.QueryFramework;

namespace Avanzis.QueryExecutor
{
    public class Database
    {
        #region QueryFrameworkDataProvider

        // Singleton instance
        private static QueryFrameworkQueryFrameworkProvider instance;

        // Lock synchronization object
        private static object syncLock = new object();

        /// <summary>
        /// Gets the current QueryProcessor based on the Dialect
        /// </summary>
        /// <value>The current.</value>
        public static QueryFrameworkQueryFrameworkProvider Provider
        {
            get
            {
                if (instance == null)
                {
                    lock (syncLock)
                    {
                        if (instance == null)
                        {
                            // TODO: IOC
                            switch (QueryFrameworkConfiguration.Dialect)
                            {
                                case Dialects.MSSql2005Dialect:
                                case Dialects.MSSql2000Dialect:
                                    instance = new Avanzis.QueryExecutor.SqlClient.MsSqlQueryFrameworkQueryFrameworkProvider();
                                    break;
                                case Dialects.MySql:
                                    instance = (QueryFrameworkQueryFrameworkProvider)Activator.CreateInstance("Avanzis.QueryFramework.MySql",
                                        "Avanzis.QueryExecutor.MySql.MySqlQueryFrameworkQueryFrameworkProvider")
                                        .Unwrap();
                                    break;
                                case Dialects.OleDb:
                                    instance = new Avanzis.QueryExecutor.OleDb.OleDbQueryFrameworkQueryFrameworkProvider();
                                    break;
                            }
                        }
                    }
                }

                return instance;
            }
        }

        /// <summary>
        /// Resets the processor.
        /// </summary>
        public static void ResetProvider()
        {
            lock (syncLock)
            {
                instance = null;
            }
        }

        #endregion

        #region ExecuteDataset

        /// <summary>
        /// Executes command and returns a Dataset
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static DataSet ExecuteDataset(string connectionString, CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteDataset(connectionString, commandType, commandText, parameters);
        }

        /// <summary>
        /// Executes the dataset.
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static DataSet ExecuteDataset(string connectionString, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteDataset(connectionString, CommandType.Text, commandText, parameters);
        }

        /// <summary>
        /// Executes the command and returns a Dataset
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static DataSet ExecuteDataset(DbConnection connection, CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteDataset(connection, commandType, commandText, parameters);
        }

        /// <summary>
        /// Executes the dataset.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static DataSet ExecuteDataset(DbConnection connection, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteDataset(connection, CommandType.Text, commandText, parameters);
        }

        /// <summary>
        /// Executes the dataset.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <returns></returns>
        public static DataSet ExecuteDataset(DbConnection connection, CommandType commandType, string commandText)
        {
            return Provider.ExecuteDataset(connection, commandType, commandText);
        }

        /// <summary>
        /// Executes the dataset.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="commandText">The command text.</param>
        /// <returns></returns>
        public static DataSet ExecuteDataset(DbConnection connection, string commandText)
        {
            return Provider.ExecuteDataset(connection, CommandType.Text, commandText);
        }

        #endregion

        #region ExecuteReader

        /// <summary>
        /// Executes the command and returns a reader
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="externalConnection">if set to <c>true</c> [external connection].</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static DbDataReader ExecuteReader(DbConnection connection, CommandType commandType, string commandText, bool externalConnection, params DbParameter[] parameters)
        {
            return Provider.ExecuteReader(connection, commandType, commandText, externalConnection, parameters);
        }

        /// <summary>
        /// Executes the reader.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="externalConnection">if set to <c>true</c> [external connection].</param>
        /// <returns></returns>
        internal static DbDataReader ExecuteReader(DbConnection connection, CommandType commandType, string commandText, bool externalConnection)
        {
            return Provider.ExecuteReader(connection, commandType, commandText, externalConnection);
        }

        /// <summary>
        /// Executes a commands and returns a reader
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static DbDataReader ExecuteReader(string connectionString, CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteReader(connectionString, commandType, commandText, parameters);           
        }

        /// <summary>
        /// Executes the reader.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static DbDataReader ExecuteReader(DbConnection connection, CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteReader(connection, commandType, commandText, true, parameters);
        }

        /// <summary>
        /// Executes a commands and returns a reader
        /// </summary>
        /// <param name="transaction">The transaction.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static DbDataReader ExecuteReader(DbTransaction transaction, CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteReader(transaction, commandType, commandText, parameters);
        }

        #endregion

        #region ExecuteNonQuery

        /// <summary>
        /// Executes a query but does not return anything
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        public static int ExecuteNonQuery(DbConnection connection, CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteNonQuery(connection, commandType, commandText, parameters);
        }

        /// <summary>
        /// Executes a query but does not return anything
        /// </summary>
        /// <param name="transaction">The transaction.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static int ExecuteNonQuery(DbTransaction transaction, CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteNonQuery(transaction, commandType, commandText, parameters);
        }

        /// <summary>
        /// Executes the non query.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static int ExecuteNonQuery(DbConnection connection, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteNonQuery(connection, CommandType.Text, commandText, parameters);
        }

        /// <summary>
        /// Executes the non query.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <returns></returns>
        public static int ExecuteNonQuery(DbConnection connection, CommandType commandType, string commandText)
        {
            return Provider.ExecuteNonQuery(connection, commandType, commandText);
        }

        /// <summary>
        /// Executes the non query.
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        public static int ExecuteNonQuery(string connectionString, CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteNonQuery(connectionString, commandType, commandText, parameters); 
        }

        /// <summary>
        /// Executes the non query.
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static int ExecuteNonQuery(string connectionString, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteNonQuery(connectionString, CommandType.Text, commandText, parameters);
        }

        #endregion

        #region ExecuteScalar

        /// <summary>
        /// Executes the command and returns a scalar
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static object ExecuteScalar(DbConnection connection, CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteScalar(connection, commandType, commandText, parameters);
        }

        /// <summary>
        /// Executes the scalar.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <returns></returns>
        public static object ExecuteScalar(DbConnection connection, CommandType commandType, string commandText)
        {
            return Provider.ExecuteScalar(connection, commandType, commandText);
        }

        /// <summary>
        /// Executes the command and returns a scalar
        /// </summary>
        /// <param name="transaction">The transaction.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static object ExecuteScalar(DbTransaction transaction, CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteScalar(transaction, commandType, commandText, parameters);
        }

        /// <summary>
        /// Executes the scalar.
        /// </summary>
        /// <param name="transaction">The transaction.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <returns></returns>
        public static object ExecuteScalar(DbTransaction transaction, CommandType commandType, string commandText)
        {
            return Provider.ExecuteScalar(transaction, commandType, commandText);
        }

        /// <summary>
        /// Executes the scalar.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static object ExecuteScalar(DbConnection connection, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteScalar(connection, CommandType.Text, commandText, parameters);
        }

        /// <summary>
        /// Executes the command and returns a scalar object
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static object ExecuteScalar(string connectionString, CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteScalar(connectionString, commandType, commandText, parameters);
        }

        /// <summary>
        /// Executes the command and returns a scalar object
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static object ExecuteScalar(string connectionString, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteScalar(connectionString, CommandType.Text, commandText, parameters);
        }

        #endregion

        #region CreateConnection

        /// <summary>
        /// Gets a connection to the Database
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        /// <returns></returns>
        public static DbConnection CreateConnection(string connectionString)
        {
            return Provider.CreateConnection(connectionString);
        }

        #endregion      

        #region ExecuteDataTable

        /// <summary>
        /// Executes command and returns a Dataset
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static DataTable ExecuteDataTable(string connectionString, CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteDataTable(connectionString, commandType, commandText, parameters);            
        }

       
        public static DataTable ExecuteDataTable(DbConnection connection, CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            return Provider.ExecuteDataTable(connection, commandType, commandText, parameters);
        }

        #endregion

        #region ExecuteDataRow

        /// <summary>
        /// Executes the data row.
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        /// <param name="commandType">Type of the command.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static DataRow ExecuteDataRow(string connectionString, CommandType commandType, string commandText, params DbParameter[] parameters)
        {
            DataTable dataTable = ExecuteDataTable(connectionString, commandType, commandText, parameters);
            return dataTable.Rows[0];
        }

        /// <summary>
        /// Executes the data row.
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        /// <param name="commandText">The command text.</param>
        /// <param name="parameters">The parameters.</param>
        /// <returns></returns>
        public static DataRow ExecuteDataRow(string connectionString, string commandText, params DbParameter[] parameters)
        {
            return ExecuteDataRow(connectionString, CommandType.Text, commandText, parameters);
        }

        #endregion

        #region CreateCommand

        public static DbCommand CreateCommand(string commandText, DbConnection connection)
        {
            return Provider.CreateCommand(commandText, connection);
        }

        #endregion

        #region CreateDataAdapter

        public static DbDataAdapter CreateDataAdapter(DbCommand command)
        {
            return Provider.CreateDataAdapter(command);
        }

        public static DbDataAdapter CreateDataAdapter(string commandText, DbConnection connection)
        {
            return Provider.CreateDataAdapter(commandText, connection);
        }

        #endregion

        #region CreateParameter

        /// <summary>
        /// Creates the parameter.
        /// </summary>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="parameterValue">The parameter value.</param>
        /// <returns></returns>
        public static DbParameter CreateParameter(string parameterName, object parameterValue)
        {
            return Provider.CreateParameter(parameterName, parameterValue);
        }

        /// <summary>
        /// Creates the parameter.
        /// </summary>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="parameterValue">The parameter value.</param>
        /// <param name="dbType">Type of the db.</param>
        /// <returns></returns>
        public static DbParameter CreateParameter(string parameterName, object parameterValue, DbType dbType)
        {
            DbParameter parameter = Provider.CreateParameter(parameterName, parameterValue);
            parameter.DbType = dbType;
            return parameter;
        }

        public static DbParameter CreateParameter(string parameterName, object parameterValue, int size)
        {
            DbParameter parameter = Provider.CreateParameter(parameterName, parameterValue);
            parameter.Size = size;
            return parameter;
        }

        #endregion
    }
}
